using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Storage;

#if !SILVERLIGHT
using Microsoft.Xna.Framework.Net;
#endif

namespace Fusion
{
    public class Engine : Microsoft.Xna.Framework.Game
    {
        #region Fields

		public static Engine instance;
        public static GraphicsDevice graphicsDevice
        {
            get
            {
                return instance.GraphicsDevice;
            }
        }
        public static ContentManager content
        {
            get
            {
                return instance.Content;
            }
        }

        public static GraphicsDeviceManager deviceManager;
        public static int BufferWidth;
        public static int BufferHeight;

		#region Sprite Batch
		static SpriteBatch batch;
        public static SpriteSortMode spriteSortMode = SpriteSortMode.Immediate;
        static bool batchHasStarted = false;
        static bool additiveBatchStarted = false;
        static bool unblendBatchStarted = false;

		static TextureFilter magFilter = TextureFilter.None;
		static TextureFilter minFilter = TextureFilter.Linear;

        public static SpriteBatch spriteBatch
        {
            get
            {
                if( batch == null )
                    batch = new SpriteBatch( instance.GraphicsDevice );

                if( batchHasStarted == false )
                {
                    EndBatch();
                    batch.Begin( SpriteBlendMode.AlphaBlend, spriteSortMode, SaveStateMode.None );
                    batchHasStarted = true;
				}

				graphicsDevice.SamplerStates[0].MagFilter = magFilter;
#if !SILVERLIGHT
				graphicsDevice.SamplerStates[0].MinFilter = minFilter;
#endif

                return batch;
            }
        }
        public static SpriteBatch additiveBatch
        {
            get
            {
                if( batch == null )
                    batch = new SpriteBatch( instance.GraphicsDevice );

                if( additiveBatchStarted == false )
                {
                    EndBatch();
                    batch.Begin( SpriteBlendMode.Additive, spriteSortMode, SaveStateMode.SaveState );
                    additiveBatchStarted = true;
				}

				graphicsDevice.SamplerStates[0].MagFilter = magFilter;
#if !SILVERLIGHT
				graphicsDevice.SamplerStates[0].MinFilter = minFilter;
#endif

                return batch;
            }
        }
        public static SpriteBatch unblendBatch
        {
            get
            {
                if( batch == null )
                    batch = new SpriteBatch( instance.GraphicsDevice );

                if( unblendBatchStarted == false )
                {
                    EndBatch();
                    batch.Begin( SpriteBlendMode.None, spriteSortMode, SaveStateMode.SaveState );
                    unblendBatchStarted = true;
                }


				graphicsDevice.SamplerStates[0].MagFilter = magFilter;
#if !SILVERLIGHT
				graphicsDevice.SamplerStates[0].MinFilter = minFilter;
#endif

                return batch;
            }
        }
        public static void EndBatch()
        {
            if( batchHasStarted == true || additiveBatchStarted == true || unblendBatchStarted == true )
                batch.End();

            batchHasStarted = false;
            additiveBatchStarted = false;
            unblendBatchStarted = false;
        }
		#endregion

		#region Resource Managers
		public static ResourceManager<Texture2D> SysTextures = new ResourceManager<Texture2D>();
        public static ResourceManager<Texture2D> Textures = new ResourceManager<Texture2D>( "Textures/", "png" );
		public static ResourceManager<SpriteFont> Fonts = new ResourceManager<SpriteFont>( "Fonts/", "ttf" );
#if !SILVERLIGHT
        public static ResourceManager<Model> Models = new ResourceManager<Model>("Models/", "x");
        public static ResourceManager<Effect> Effects = new ResourceManager<Effect>("Effects/", "fx");
#endif

		public static ResourceManager<SoundEffect> Sounds = new ResourceManager<SoundEffect>( "Sounds/", "wav" );
		public static ResourceManager<TileSheet> Sheets = new ResourceManager<TileSheet>();
		public static ResourceManager<AnimationData> AnimationData = new ResourceManager<AnimationData>();
		#endregion
		
		public static GamerServicesComponent gamerServices;

        public static float period;

		public static VoidDelegate Timers;
		public static Ticker AnimationTicker; // 

        #endregion

		#region Methods

		/// <summary> Constructor </summary>
        public Engine()
        {
            instance = this;

            deviceManager = new GraphicsDeviceManager( this );
            Content.RootDirectory = "Content";

            Components.Add( gamerServices = new GamerServicesComponent( this ) );
        }

        /// <summary> Does Initialization on the engine </summary>
        protected override void Initialize()
        {
            #region Graphics
            deviceManager.IsFullScreen = false;
			
#if !SILVERLIGHT
            deviceManager.MinimumVertexShaderProfile = ShaderProfile.VS_2_0;
#endif
            deviceManager.SynchronizeWithVerticalRetrace = false;
            IsFixedTimeStep = false;

            graphicsDevice.RenderState.AlphaBlendEnable = true;
            graphicsDevice.RenderState.DepthBufferEnable = true;
            graphicsDevice.RenderState.DepthBufferFunction = CompareFunction.Greater;
            deviceManager.ApplyChanges();

            #endregion

            base.Initialize();
        }

		protected override void LoadContent()
		{
			// Load animations
			XElement doc = Secretary.Load( @"Content/Data/Animations.xml" );
			foreach( XElement element in doc.Descendants() )
			{
				if( element.Name == "Animation" )
				{
					AnimationData data = new AnimationData( element );
					AnimationData.Add( data.name, data );
				}
			}

			base.LoadContent();
		}

        /// <summary> Unloads all content from memory </summary>
        protected override void UnloadContent()
        {
            // Dispose of textures
            foreach( Texture2D texture in Textures.data.Values )
                texture.Dispose();
            Textures.data.Clear();
        }


        /// <summary> Engine update loop </summary>
        protected override void Update( GameTime time )
		{
			// Set current frame period
			period = (float)time.ElapsedGameTime.TotalSeconds;

			// Update Input
			Input.Update();

			// Update Sound
			Noisemaker.Update();

			// Update Timers
			if( Timers != null )
				Timers();

			if( this.IsActive )
			{
				if( AnimationTicker != null )
					AnimationTicker.Update();
			}

            // Do some Other Things
            base.Update( time );
        }


        /// <summary> Engine draw loop </summary>
        protected override void Draw( GameTime time )
        {
            base.Draw( time );
		}

		#endregion
	}
}
